package com.samuel.basics.utils;

import com.samuel.basics.constant.CommonConstant;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

/**
 * ip相关工具
 *
 * @author kaiji
 * @since 2019-10-30
 */
public class IpUtils {

    private static final String X_FORWARDED_FOR = "x-forwarded-for";
    private static final String LOCAL_IP = "0:0:0:0:0:0:0:1";
    private static final String MATCHER_255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
    private static final Pattern PATTERN = Pattern.compile("^(?:" + MATCHER_255 + "\\.){3}" + MATCHER_255 + "$");

    private static long ipV4ToLong(String ip) {
        String[] octets = ip.split("\\.");
        return (Long.parseLong(octets[0]) << 24) + ((long) Integer.parseInt(octets[1]) << 16)
                + ((long) Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
    }

    /**
     * 验证是否是IP4
     *
     * @param ip
     *      ip地址
     * @return  true：是 false：不是
     */
    private static boolean ipv4Private(String ip) {
        long longIp = ipV4ToLong(ip);
        return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))
                || (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))
                || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
    }

    /**
     * 验证是否是IP4
     *
     * @param ip
     *      ip地址
     * @return  true：是 false：不是
     */
    private static boolean ipv4Valid(String ip) {
        return PATTERN.matcher(ip).matches();
    }

    /**
     * 获取IP地址
     *
     * @param request
     *      request域对象
     * @return  ip地址
     */
    public static String getIpFromRequest(HttpServletRequest request) {
        String ip;
        if (null == request) {
            return "un_know_ip";
        }
        boolean found = false;
        if ((ip = request.getHeader(X_FORWARDED_FOR)) != null) {
        	StringTokenizer tokenizer = new StringTokenizer(ip, CommonConstant.DOC_FLAG);
            while (tokenizer.hasMoreTokens()) {
                ip = tokenizer.nextToken().trim();
                if (ipv4Valid(ip) && !ipv4Private(ip)) {
                    found = true;
                    break;
                }
            }
        }
        if (!found) {
            ip = request.getRemoteAddr();
        }
        if (StringUtils.equals(LOCAL_IP, ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }
}
